package controller

import (
	"backend/internal/service"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type EvidenceController struct {
	evidenceService *service.EvidenceService
}

func NewEvidenceController(service *service.EvidenceService) *EvidenceController {
	return &EvidenceController{evidenceService: service}
}

// 统一错误处理
func (ec *EvidenceController) handleFabricError(c *gin.Context, err error) {
	statusCode := http.StatusInternalServerError
	switch {
	case strings.Contains(err.Error(), "not found"):
		statusCode = http.StatusNotFound
	case strings.Contains(err.Error(), "exists"):
		statusCode = http.StatusConflict
	case strings.Contains(err.Error(), "invalid"):
		statusCode = http.StatusBadRequest
	}

	c.JSON(statusCode, gin.H{
		"success": false,
		"error":   err.Error(),
	})
}

// -------------------- 重构后的业务方法 --------------------

func (ec *EvidenceController) Initialize(ctx *gin.Context) {
	chainID := ctx.Query("chainId")

	if err := ec.evidenceService.InitializeLedger(chainID); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) CreateSideChainLock(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req CreateSideChainLockRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	lockHash, err := ec.evidenceService.CreateSideChainLock(
		chainID,
		req.ClientID,
		req.Seed,
		req.Timeout,
		req.DataHash,
		req.EvidenceID,
	)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, LockResponse{
		BaseResponse: BaseResponse{Success: true},
		LockHash:     lockHash,
	})
}

func (ec *EvidenceController) CreateMainChainLock(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req CreateMainChainLockRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	err := ec.evidenceService.CreateMainChainLock(
		chainID,
		req.HashValue,
		req.ClientID,
		req.Timeout,
		req.DataHash,
		req.EvidenceData,
		req.EvidenceID,
		req.SidechainChainID,
	)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) VerifyAndUnlock(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req VerifyUnlockRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	err := ec.evidenceService.VerifyAndUnlock(
		chainID,
		req.LockKey,
		req.Preimage,
	)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) SubmitSideChainData(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req SubmitSidechainDataRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	err := ec.evidenceService.SubmitSideChainData(
		chainID,
		req.DataHash,
		req.EvidenceData,
		req.EvidenceID,
	)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) GetEvidence(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	evidenceID := ctx.Param("id")

	result, err := ec.evidenceService.GetEvidence(chainID, evidenceID)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	var evidence map[string]interface{}
	if err := json.Unmarshal([]byte(result), &evidence); err != nil {
		ec.handleFabricError(ctx, fmt.Errorf("解析存证数据失败"))
		return
	}

	ctx.JSON(http.StatusOK, EvidenceResponse{
		BaseResponse: BaseResponse{Success: true},
		Data:         evidence,
	})
}

func (ec *EvidenceController) GetAllEvidences(ctx *gin.Context) {
	chainID := ctx.Query("chainId")

	rawData, err := ec.evidenceService.GetAllEvidences(chainID)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	var evidences []map[string]interface{}
	for _, item := range rawData {
		var record map[string]interface{}
		if err := json.Unmarshal([]byte(item), &record); err != nil {
			ec.handleFabricError(ctx, fmt.Errorf("数据解析失败"))
			return
		}
		evidences = append(evidences, record)
	}

	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(ctx.DefaultQuery("pageSize", "10"))

	start := (page - 1) * pageSize
	if start > len(evidences) {
		start = len(evidences)
	}
	end := start + pageSize
	if end > len(evidences) {
		end = len(evidences)
	}
	pagedData := evidences[start:end]

	ctx.JSON(http.StatusOK, EvidenceListResponse{
		BaseResponse: BaseResponse{Success: true},
		Total:        len(evidences),
		Evidences:    pagedData,
		Page:         page,
		PageSize:     pageSize,
	})
}

func (ec *EvidenceController) TimeoutRollback(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req TimeoutRollbackRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	err := ec.evidenceService.TimeoutRollback(chainID, req.LockKey)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) GetUnsyncedRecords(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	sideChainID := ctx.Query("sideChainId")

	records, err := ec.evidenceService.GetUnsyncedRecords(chainID, sideChainID)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	var stats struct {
		Total     int `json:"total"`
		Available int `json:"available"`
		Expired   int `json:"expired"`
	}

	for _, record := range records {
		if status, ok := record["Status"].(string); ok {
			switch status {
			case "AVAILABLE":
				stats.Available++
			case "EXPIRED":
				stats.Expired++
			}
		}
		stats.Total++
	}

	ctx.JSON(http.StatusOK, UnsyncedRecordsResponse{
		BaseResponse: BaseResponse{Success: true},
		Stats:        stats,
		Records:      records,
	})
}

func (ec *EvidenceController) ConfirmSync(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req ConfirmSyncRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	err := ec.evidenceService.ConfirmSync(chainID, req.EvidenceID)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) VerifyStorageProof(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req VerifyProofRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	err := ec.evidenceService.VerifyStorageProof(chainID, req.ProofStr)
	if err != nil {
		ec.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (ec *EvidenceController) BatchSyncEvidences(ctx *gin.Context) {
	var req BatchSyncRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ec.handleFabricError(ctx, fmt.Errorf("请求参数无效: %v", err))
		return
	}

	if req.SideChainID == "" {
		ec.handleFabricError(ctx, fmt.Errorf("缺少必要的sideChainID参数"))
		return
	}

	records, err := ec.evidenceService.GetUnsyncedRecords(req.MainChainID, req.SideChainID)
	if err != nil {
		ec.handleFabricError(ctx, fmt.Errorf("获取未同步记录失败: %v", err))
		return
	}

	if len(records) == 0 {
		ctx.JSON(http.StatusOK, BatchSyncResponse{
			BaseResponse: BaseResponse{Success: true},
			Total:        0,
			Synced:       0,
			Skipped:      0,
			Failed:       0,
		})
		return
	}

	var (
		syncedCount  int
		skippedCount int
		failedCount  int
		failedItems  []BatchSyncFailure
	)

	for _, record := range records {
		evidenceID, ok1 := record["EvidenceID"].(string)
		dataHash, ok2 := record["DataHash"].(string)
		evidenceData, ok3 := record["EvidenceData"].(string)

		if !ok1 || !ok2 || !ok3 {
			skippedCount++
			failedItems = append(failedItems, BatchSyncFailure{
				EvidenceID: evidenceID,
				Reason:     "记录字段不完整",
			})
			continue
		}

		seed := time.Now().UnixNano()
		lockHash, err := ec.evidenceService.CreateSideChainLock(
			req.SideChainID,
			"sync-client",
			seed,
			300,
			dataHash,
			evidenceID,
		)
		if err != nil {
			failedCount++
			failedItems = append(failedItems, BatchSyncFailure{
				EvidenceID: evidenceID,
				Reason:     fmt.Sprintf("创建侧链锁失败: %v", err),
			})
			continue
		}

		err = ec.evidenceService.CreateMainChainLock(
			req.MainChainID,
			lockHash,
			"sync-client",
			300,
			dataHash,
			evidenceData,
			evidenceID,
			req.SideChainID,
		)
		if err != nil {
			failedCount++
			failedItems = append(failedItems, BatchSyncFailure{
				EvidenceID: evidenceID,
				Reason:     fmt.Sprintf("创建主链锁失败: %v", err),
			})
			continue
		}

		lockKey := fmt.Sprintf("lock_sync-client_%s", lockHash)
		err = ec.evidenceService.VerifyAndUnlock(
			req.SideChainID,
			lockKey,
			strconv.FormatInt(seed, 10),
		)
		if err != nil {
			failedCount++
			failedItems = append(failedItems, BatchSyncFailure{
				EvidenceID: evidenceID,
				Reason:     fmt.Sprintf("解锁失败: %v", err),
			})
			continue
		}

		err = ec.evidenceService.ConfirmSync(
			req.MainChainID,
			evidenceID,
		)
		if err != nil {
			failedCount++
			failedItems = append(failedItems, BatchSyncFailure{
				EvidenceID: evidenceID,
				Reason:     fmt.Sprintf("确认同步失败: %v", err),
			})
			continue
		}

		syncedCount++
	}

	ctx.JSON(http.StatusOK, BatchSyncResponse{
		BaseResponse: BaseResponse{Success: true},
		Total:        len(records),
		Synced:       syncedCount,
		Skipped:      skippedCount,
		Failed:       failedCount,
		FailedItems:  failedItems,
	})
}

// -------------------- 请求结构体 --------------------
type BaseResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message,omitempty"`
	Error   string `json:"error,omitempty"`
}

type CreateSideChainLockRequest struct {
	ClientID   string `json:"clientID" binding:"required"`
	Seed       int64  `json:"seed" binding:"required"`
	Timeout    int    `json:"timeout" binding:"required,min=60"`
	DataHash   string `json:"dataHash" binding:"required"`
	EvidenceID string `json:"evidenceID" binding:"required"`
}

type CreateMainChainLockRequest struct {
	HashValue        string `json:"hashValue" binding:"required"`
	ClientID         string `json:"clientID" binding:"required"`
	Timeout          int    `json:"timeout" binding:"required,min=60"`
	DataHash         string `json:"dataHash" binding:"required"`
	EvidenceData     string `json:"evidenceData" binding:"required"`
	EvidenceID       string `json:"evidenceID" binding:"required"`
	SidechainChainID string `json:"sidechainChainID" binding:"required"`
}

type VerifyUnlockRequest struct {
	LockKey  string `json:"lockKey" binding:"required"`
	Preimage string `json:"preimage" binding:"required"`
}

type SubmitSidechainDataRequest struct {
	DataHash     string `json:"dataHash" binding:"required"`
	EvidenceData string `json:"evidenceData" binding:"required"`
	EvidenceID   string `json:"evidenceID" binding:"required"`
}

type LockResponse struct {
	BaseResponse
	LockHash string `json:"lockHash"`
}

type EvidenceResponse struct {
	BaseResponse
	Data map[string]interface{} `json:"data"`
}

type EvidenceListResponse struct {
	BaseResponse
	Total     int                      `json:"total"`
	Evidences []map[string]interface{} `json:"evidences"`
	Page      int                      `json:"page"`
	PageSize  int                      `json:"pageSize"`
}

type TimeoutRollbackRequest struct {
	LockKey string `json:"lockKey" binding:"required"`
}

type ConfirmSyncRequest struct {
	EvidenceID string `json:"evidenceID" binding:"required"`
}

type VerifyProofRequest struct {
	ProofStr string `json:"proofStr"`
}

type UnsyncedRecordsResponse struct {
	BaseResponse
	Stats struct {
		Total     int `json:"total"`
		Available int `json:"available"`
		Expired   int `json:"expired"`
	} `json:"stats"`
	Records []map[string]interface{} `json:"records"`
}

type BatchSyncResponse struct {
	BaseResponse
	Total       int                `json:"total"`
	Synced      int                `json:"synced"`
	Skipped     int                `json:"skipped"`
	Failed      int                `json:"failed"`
	FailedItems []BatchSyncFailure `json:"failedItems,omitempty"`
}

type BatchSyncFailure struct {
	EvidenceID string `json:"evidenceId"`
	Reason     string `json:"reason"`
}

// 新增的批量同步请求结构体
type BatchSyncRequest struct {
	MainChainID string `json:"mainChainId" binding:"required"`
	SideChainID string `json:"sideChainId" binding:"required"`
}
